home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / EC.C < prev    next >
C/C++ Source or Header  |  1993-08-09  |  9KB  |  360 lines

  1. /* Driver for 3COM Ethernet card
  2.  * PC specific code
  3.  */
  4.  
  5. #define    TIMER    20000    /* Timeout on transmissions */
  6.  
  7. #include <stdio.h>
  8. #include <dos.h>
  9. #include "global.h"
  10. #include "config.h"
  11. #ifdef PC_EC
  12. #include "mbuf.h"
  13. #include "enet.h"
  14. #include "iface.h"
  15. #include "pktdrvr.h"
  16. #include "netuser.h"
  17. #include "ec.h"
  18. #include "timer.h"
  19. #include "arp.h"
  20. #include "trace.h"
  21. #include "pc.h"
  22.  
  23. #ifndef inportw                /* previously in global.h */
  24. #define inportw inport
  25. #endif
  26.  
  27. static int near ec_init __ARGS((struct iface *iface,unsigned bufsize));
  28. static int ec_raw __ARGS((struct iface *iface,struct mbuf *bp));
  29. static int ec_stop __ARGS((struct iface *iface,int tmp));
  30. static void near getecaddr __ARGS((unsigned base,char *cp));
  31. static void near rcv_fixup __ARGS((unsigned base));
  32. static void near setecaddr __ARGS((unsigned base,char *cp));
  33.  
  34. static INTERRUPT (*Ecvecsave[EC_MAX])();
  35. static INTERRUPT (*Ecvec[])() = {ec0vec,ec1vec,ec2vec};
  36.  
  37. static struct ec Ec[EC_MAX];       /* Per-controller info */
  38. static int Nec = 0;
  39.  
  40. /* Initialize interface */
  41. static int near
  42. ec_init(iface,bufsize)
  43. struct iface *iface;
  44. unsigned bufsize;    /* Maximum size of receive queue in PACKETS */
  45. {
  46.     int dev = iface->dev;
  47.     struct ec *ecp = &Ec[dev];
  48.     unsigned base = ecp->base;
  49.  
  50.     ecp->iface = iface;
  51.  
  52.     /* Pulse IE_RESET */
  53.      outportb(IE_CSR(base),IE_RESET);
  54.  
  55.     /* Save old int vector */
  56.     Ecvecsave[dev] = getirq(ecp->vec);
  57.  
  58.     /* Set interrupt vector */
  59.     if(setirq(ecp->vec,Ecvec[dev]) == -1){
  60.         tprintf("IRQ %u out of range\n",ecp->vec);
  61.         return -1;
  62.     }
  63.     maskon(ecp->vec);    /* Enable interrupt */
  64.     if(iface->hwaddr == NULLCHAR)
  65.         iface->hwaddr = mxallocw(EADDR_LEN);
  66.     getecaddr(base,iface->hwaddr);
  67.     setecaddr(base,iface->hwaddr);
  68.     if(memcmp(iface->hwaddr,Ether_bdcst,EADDR_LEN) == 0){
  69.         tputs("EC address PROM contains broadcast address!!\n");
  70.         return -1;
  71.     }
  72.     /* Enable DMA/interrupt request, gain control of buffer */
  73.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  74.  
  75.     /* Enable transmit interrupts */
  76.     outportb(EDLC_XMT(base),EDLC_16 | EDLC_JAM);
  77.  
  78.     /* Set up the receiver interrupts and flush status */
  79.     outportb(EDLC_RCV(base),
  80.       EDLC_MULTI|EDLC_GOOD|EDLC_ANY|EDLC_SHORT|EDLC_DRIBBLE|EDLC_FCS|EDLC_OVER);
  81.     inportb(EDLC_RCV(base));
  82.  
  83.     /* Start receiver */
  84.     outport(IE_RP(base),0);    /* Reset read pointer */
  85.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  86.     return 0;
  87. }
  88.  
  89. /* Send raw packet (caller provides header) */
  90. static int
  91. ec_raw(iface,bp)
  92. struct iface *iface;    /* Pointer to interface control block */
  93. struct mbuf *bp;        /* Data field */
  94. {
  95.     int i;
  96.     struct ec *ecp = &Ec[iface->dev];
  97.     unsigned base = ecp->base;
  98.     short size = len_p(bp);
  99.  
  100.     dump(iface,IF_TRACE_OUT,CL_ETHERNET,bp);
  101.  
  102.     ecp->estats.xmit++;
  103.  
  104.     /* Pad the size out to the minimum, if necessary,
  105.      * with junk from the last packet (nice security hole here)
  106.      */
  107.     if(size < RUNT)
  108.         size = RUNT;
  109.  
  110.     size = (size+1) & ~1;    /* round size up to next even number */
  111.  
  112.     /* Wait for transmitter ready, if necessary. IE_XMTBSY is valid
  113.      * only in the transmit mode, hence the initial check.
  114.      */
  115.     if((inportb(IE_CSR(base)) & IE_BUFCTL) == IE_XMTEDLC){
  116.         for(i = TIMER; (inportb(IE_CSR(base)) & IE_XMTBSY) && i != 0; i--)
  117.             ;
  118.         if(i == 0) {
  119.             ecp->estats.timeout++;
  120.             free_p(bp);
  121.             return -1;
  122.         }
  123.     }
  124.     ecp->size = size;
  125.     /* Get control of the board buffer and disable receiver */
  126.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  127.     /* Point GP at beginning of packet */
  128.     outport(IE_GP(base),BFRSIZ-size);
  129.     /* Actually load each piece with a fast assembler routine */
  130.     while(bp != NULLBUF){
  131.         outbuf(IE_BFR(base),bp->data,bp->cnt);
  132.         bp = free_mbuf(bp);
  133.     }
  134.     /* Start transmitter */
  135.     outport(IE_GP(base),BFRSIZ-size);
  136.     outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  137.     return 0;
  138. }
  139.  
  140. /* Ethernet interrupt handler */
  141. void
  142. ecint(dev)
  143. int dev;
  144. {
  145.     struct mbuf *bp;
  146.     int16 size;
  147.     char stat;
  148.     struct phdr *phdr;
  149.  
  150.     struct ec *ecp = &Ec[dev];
  151.     unsigned base = ecp->base;
  152.  
  153.     ecp->estats.intrpt++;
  154.  
  155.     /* Check for transmit jam */
  156.     if(!(inportb(IE_CSR(base)) & IE_XMTBSY)){
  157.         stat = inportb(EDLC_XMT(base));
  158.         if(stat & EDLC_16){
  159.             ecp->estats.jam16++;
  160.             rcv_fixup(base);
  161.         } else if(stat & EDLC_JAM){
  162.             /* Crank counter back to beginning and restart transmit */
  163.             ecp->estats.jam++;
  164.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  165.             outport(IE_GP(base),BFRSIZ - ecp->size);
  166.             outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  167.         }
  168.     }
  169.     for(;;){
  170.         stat = inportb(EDLC_RCV(base));
  171.         if(stat & EDLC_STALE)
  172.             break;
  173.  
  174.         if(stat & EDLC_OVER){
  175.             ecp->estats.over++;
  176.             rcv_fixup(base);
  177.             continue;
  178.         }
  179.         if(stat & (EDLC_SHORT | EDLC_FCS | EDLC_DRIBBLE)){
  180.             ecp->estats.bad++;
  181.             rcv_fixup(base);
  182.             continue;
  183.         }
  184.         if(stat & EDLC_ANY){
  185.             /* Get control of the buffer */
  186.             outport(IE_GP(base),0);
  187.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  188.  
  189.             /* Allocate mbuf and copy the packet into it */
  190.             size = inportw(IE_RP(base));
  191.             if(size < RUNT || size > GIANT)
  192.                 ecp->estats.bad++;
  193.             else if((bp = alloc_mbuf(size+sizeof(struct phdr))) == NULLBUF)
  194.                 ecp->estats.nomem++;
  195.             else {
  196.                 ecp->estats.recv++;
  197.                 /* Generate descriptor header */
  198.                 phdr = (struct phdr *)bp->data;
  199.                 phdr->iface = ecp->iface;
  200.                 phdr->type = CL_ETHERNET;
  201.  
  202.                 inbuf(IE_BFR(base),bp->data+sizeof(struct phdr),size);
  203.                 bp->cnt = size + sizeof(struct phdr);
  204.                 enqueue(&Hopper,bp);
  205.             }
  206.             outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  207.             outportb(IE_RP(base),0);
  208.         }
  209.     }
  210.     /* Clear any spurious interrupts */
  211.     (void)inportb(EDLC_RCV(base));
  212.     (void)inportb(EDLC_XMT(base));
  213. }
  214.  
  215. static void near
  216. rcv_fixup(base)
  217. unsigned base;
  218. {
  219.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  220.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  221.     outportb(IE_RP(base),0);
  222. }
  223.  
  224. /* Read Ethernet address from controller PROM */
  225. static void near
  226. getecaddr(base,cp)
  227. unsigned base;
  228. char *cp;
  229. {
  230.     int i;
  231.  
  232.     for(i = 0; i < EADDR_LEN; i++) {
  233.         outport(IE_GP(base),i);
  234.         *cp++ = inportb(IE_SAPROM(base));
  235.     }
  236. }
  237.  
  238. /* Set Ethernet address on controller */
  239. static void near
  240. setecaddr(base,cp)
  241. unsigned base;
  242. char *cp;
  243. {
  244.     int i;
  245.  
  246.     for(i = 0; i < EADDR_LEN; i++)
  247.         outportb(EDLC_ADDR(base)+i,*cp++);
  248. }
  249.  
  250. /* Shut down the Ethernet controller */
  251. static int
  252. ec_stop(iface,tmp)
  253. struct iface *iface;
  254. int tmp;
  255. {
  256.     int dev = iface->dev;
  257.     struct ec *ecp = &Ec[dev];
  258.     unsigned base = ecp->base;
  259.  
  260.     /* Disable interrupt */
  261.     maskoff(Ec[dev].vec);
  262.  
  263.     /* Restore original interrupt vector */
  264.     setirq(ecp->vec,Ecvecsave[dev]);
  265.  
  266.     /* Pulse IE_RESET */
  267.     outportb(IE_CSR(base),IE_RESET);
  268.     outportb(IE_CSR(base),0);
  269.     return 0;
  270. }
  271.  
  272. /* Attach a 3-Com model 3C500 Ethernet controller to the system
  273.  * argv[0]: hardware type, must be "3c500"
  274.  * argv[1]: I/O address, e.g., "0x300"
  275.  * argv[2]: vector, e.g., "3"
  276.  * argv[3]: mode, must be "arpa"
  277.  * argv[4]: interface label, e.g., "ec0"
  278.  * argv[5]: maximum number of packets allowed on receive queue, e.g., "5"
  279.  * argv[6]: maximum transmission unit, bytes, e.g., "1500"
  280.  *  notused:
  281.  * argv[7]: IP address, optional (defaults to Ip_addr)
  282.  */
  283. int
  284. ec_attach(argc,argv,p)
  285. int argc;
  286. char *argv[];
  287. void *p;
  288. {
  289.     struct iface *if_ec;
  290.     int dev;
  291.  
  292.     if(stricmp(argv[3],"arpa") != 0){
  293.         tputs("Mode must be arpa\n");
  294.         return -1;
  295.     }
  296.     if(if_lookup(argv[4]) != NULLIF) {
  297.         tprintf(Ifexist,argv[4]);
  298.         return -1;
  299.     }
  300.     if(Nec >= EC_MAX){
  301.         tprintf("Max %d Ethernet controller/s\n",EC_MAX);
  302.         return -1;
  303.     }
  304.     dev = Nec++;
  305.     if_ec = mxallocw(sizeof(struct iface));
  306.     if_ec->addr = Ip_addr;
  307.     setencap(if_ec, "Ethernet");
  308.     if_ec->name = strxdup(argv[4]);
  309.     if_ec->mtu = atoi(argv[6]);
  310.     if_ec->type = CL_ETHERNET;
  311.     if_ec->send = enet_send;
  312.     if_ec->output = enet_output;
  313.     if_ec->raw = ec_raw;
  314.     if_ec->stop = ec_stop;
  315.     if_ec->dev = dev;
  316.  
  317.     Ec[dev].base = htoi(argv[1]);
  318.     Ec[dev].vec = htoi(argv[2]);
  319.  
  320.     /* Initialize device */
  321.     if(ec_init(if_ec,(unsigned)atoi(argv[5])) != 0){
  322.         xfree(if_ec->name);
  323.         xfree(if_ec);
  324.         return -1;
  325.     }
  326.     if_ec->next = Ifaces;
  327.     Ifaces = if_ec;
  328.     if_ec->niface = Niface++;
  329.     return 0;
  330. }
  331.  
  332. int
  333. doetherstat(argc,argv,p)
  334. int argc;
  335. char *argv[];
  336. void *p;
  337. {
  338.     struct ec *ecp;
  339.     char buf[20];
  340.  
  341.     for(ecp = Ec;ecp < &Ec[Nec]; ecp++){
  342.         pether(buf,ecp->iface->hwaddr);
  343.         tprintf("Controller %u, Ethernet address %s\n",
  344.         (unsigned int)((ecp-Ec) / sizeof(struct ec)),buf);
  345.  
  346.         tprintf("recv      bad       overf     drop      nomem     intrpt\n"
  347.                 "%-10lu%-10lu%-10lu%-10lu%-10lu%-10lu\n",
  348.          ecp->estats.recv,ecp->estats.bad,ecp->estats.over,
  349.          ecp->estats.drop,ecp->estats.nomem,ecp->estats.intrpt);
  350.  
  351.         tprintf("xmit      timeout   jam       jam16\n"
  352.                 "%-10lu%-10lu%-10lu%-10lu\n",
  353.          ecp->estats.xmit,ecp->estats.timeout,ecp->estats.jam,
  354.          ecp->estats.jam16);
  355.     }
  356.     return 0;
  357. }
  358.  
  359. #endif /* PC_EC */
  360.